<html>
<head>
<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Download the Simple Test testing framework - Unit tests
and mock objects for PHP</title>
<link rel="stylesheet" type="text/css" href="docs.css" title="Styles">
</head>
<body>
<div class="menu_back">
<div class="menu"><span class="chosen">SimpleTest</span> | <a
	href="overview.html">Overview</a> | <a
	href="unit_test_documentation.html">Unit tester</a> | <a
	href="group_test_documentation.html">Group tests</a> | <a
	href="mock_objects_documentation.html">Mock objects</a> | <a
	href="partial_mocks_documentation.html">Partial mocks</a> | <a
	href="reporter_documentation.html">Reporting</a> | <a
	href="expectation_documentation.html">Expectations</a> | <a
	href="web_tester_documentation.html">Web tester</a> | <a
	href="form_testing_documentation.html">Testing forms</a> | <a
	href="authentication_documentation.html">Authentication</a> | <a
	href="browser_documentation.html">Scriptable browser</a></div>
</div>
<h1>Simple Test for PHP</h1>
This page...
<ul>
	<li><a href="#unit">Using unit tester</a> with an example.</li>
	<li><a href="#group">Grouping tests</a> for testing with one
	click.</li>
	<li><a href="#mock">Using mock objects</a> to ease testing and
	gain tighter control.</li>
	<li><a href="#web">Testing web pages</a> at the browser level.</li>
</ul>
<div class="content">


<p>The following assumes that you are familiar with the concept of
unit testing as well as the PHP web development language. It is a guide
for the impatient new user of <a
	href="https://sourceforge.net/project/showfiles.php?group_id=76550">SimpleTest</a>.
For fuller documentation, especially if you are new to unit testing see
the ongoing <a href="unit_test_documentation.html">documentation</a>,
and for example test cases see the <a
	href="http://www.lastcraft.com/first_test_tutorial.php">unit
testing tutorial</a>.</p>

<p><a class="target" name="unit">
<h2>Using the tester quickly</h2>
</a></p>
<p>Amongst software testing tools, a unit tester is the one closest
to the developer. In the context of agile development the test code sits
right next to the source code as both are written simultaneously. In
this context SimpleTest aims to be a complete PHP developer test
solution and is called "Simple" because it should be easy to use and
extend. It wasn't a good choice of name really. It includes all of the
typical functions you would expect from <a href="http://www.junit.org/">JUnit</a>
and the <a href="http://sourceforge.net/projects/phpunit/">PHPUnit</a>
ports, but also adds <a href="http://www.mockobjects.com">mock
objects</a>. It has some <a href="http://sourceforge.net/projects/jwebunit/">JWebUnit</a>
functionality as well. This includes web page navigation, cookie testing
and form submission.</p>
<p>The quickest way to demonstrate is with an example.</p>
<p>Let us suppose we are testing a simple file logging class called
<span class="new_code">Log</span> in <em>classes/log.php</em>. We start
by creating a test script which we will call <em>tests/log_test.php</em>
and populate it as follows...
<pre>
&lt;?php<strong>
require_once('simpletest/unit_tester.php');
require_once('simpletest/reporter.php');
require_once('../classes/log.php');

class TestOfLogging extends UnitTestCase {
}</strong>
?&gt;
</pre> Here the <em>simpletest</em> folder is either local or in the path. You
would have to edit these locations depending on where you placed the
toolset. The <span class="new_code">TestOfLogging</span> is our frst
test case and it's currently empty.
</p>
<p>Now we have five lines of scaffolding code and still no tests.
However from this part on we get return on our investment very quickly.
We'll assume that the <span class="new_code">Log</span> class takes the
file name to write to in the constructor and we have a temporary folder
in which to place this file...
<pre>
&lt;?php
require_once('simpletest/unit_tester.php');
require_once('simpletest/reporter.php');
require_once('../classes/log.php');

class TestOfLogging extends UnitTestCase {
    <strong>
    function testCreatingNewFile() {
        @unlink('/temp/test.log');
        $log = new Log('/temp/test.log');
        $this-&gt;assertFalse(file_exists('/temp/test.log'));
        $log-&gt;message('Should write this to a file');
        $this-&gt;assertTrue(file_exists('/temp/test.log'));
    }</strong>
}
?&gt;
</pre> When a test case runs it will search for any method that starts with
the string <span class="new_code">test</span> and execute that method.
We would normally have more than one test method of course. Assertions
within the test methods trigger messages to the test framework which
displays the result immediately. This immediate response is important,
not just in the event of the code causing a crash, but also so that <span
	class="new_code">print</span> statements can display their content
right next to the test case concerned.
</p>
<p>To see these results we have to actually run the tests. If this
is the only test case we wish to run we can achieve it with...
<pre>
&lt;?php
require_once('simpletest/unit_tester.php');
require_once('simpletest/reporter.php');
require_once('../classes/log.php');

class TestOfLogging extends UnitTestCase {
    
    function testCreatingNewFile() {
        @unlink('/temp/test.log');
        $log = new Log('/temp/test.log');
        $this-&gt;assertFalse(file_exists('/temp/test.log'));
        $log-&gt;message('Should write this to a file');
        $this-&gt;assertTrue(file_exists('/temp/test.log'));
    }
}
<strong>
$test = &amp;new TestOfLogging();
$test-&gt;run(new HtmlReporter());</strong>
?&gt;
</pre>
</p>
<p>On failure the display looks like this...
<div class="demo">
<h1>testoflogging</h1>
<span class="fail">Fail</span>: testcreatingnewfile-&gt;True assertion
failed.<br>
<div
	style="padding: 8px; margin-top: 1em; background-color: red; color: white;">1/1
test cases complete. <strong>1</strong> passes and <strong>1</strong>
fails.</div>
</div>
...and if it passes like this...
<div class="demo">
<h1>testoflogging</h1>
<div
	style="padding: 8px; margin-top: 1em; background-color: green; color: white;">1/1
test cases complete. <strong>2</strong> passes and <strong>0</strong>
fails.</div>
</div>
And if you get this...
<div class="demo"><b>Fatal error</b>: Failed opening required
'../classes/log.php' (include_path='') in <b>/home/marcus/projects/lastcraft/tutorial_tests/Log/tests/log_test.php</b>
on line <b>7</b></div>
it means you're missing the <em>classes/Log.php</em> file that could
look like... <pre>
&lt;?php
class Log {
    
        function Log($file_path) {
        }

		function message() {
		}
}
?&gt;;
</pre>
</p>

<p><a class="target" name="group">
<h2>Building group tests</h2>
</a></p>
<p>It is unlikely in a real application that we will only ever run
one test case. This means that we need a way of grouping cases into a
test script that can, if need be, run every test in the application.</p>
<p>Our first step is to strip the includes and to undo our previous
hack...
<pre>
&lt;?php<strong>
require_once('../classes/log.php');</strong>

class TestOfLogging extends UnitTestCase {
    
    function testCreatingNewFile() {
        @unlink('/temp/test.log');
        $log = new Log('/temp/test.log');
        $this-&gt;assertFalse(file_exists('/temp/test.log'));
        $log-&gt;message('Should write this to a file');
        $this-&gt;assertTrue(file_exists('/temp/test.log'));<strong>
    }
}
?&gt;</strong>
</pre> Next we create a new file called <em>tests/all_tests.php</em> and
insert the following code... <pre>
<strong>&lt;?php
require_once('simpletest/unit_tester.php');
require_once('simpletest/reporter.php');

$test = &amp;new TestSuite('All tests');
$test-&gt;addTestFile('log_test.php');
$test-&gt;run(new HtmlReporter());
?&gt;</strong>
</pre> The method <span class="new_code">TestSuite::addTestFile()</span> will
include the test case file and read any new classes created that are
descended from <span class="new_code">SimpleTestCase</span>, of which <span
	class="new_code">UnitTestCase</span> is one example. Just the class
names are stored for now, so that the test runner can instantiate the
class when it works its way through your test suite.
</p>
<p>For this to work properly the test case file should not blindly
include any other test case extensions that do not actually run tests.
This could result in extra test cases being counted during the test run.
Hardly a major problem, but to avoid this inconvenience simply add a <span
	class="new_code">SimpleTestOptions::ignore()</span> directive somewhere
in the test case file. Also the test case file should not have been
included elsewhere or no cases will be added to this group test. This
would be a more serious error as if the test case classes are already
loaded by PHP the <span class="new_code">TestSuite::addTestFile()</span>
method will not detect them.</p>
<p>To display the results it is necessary only to invoke <em>tests/all_tests.php</em>
from the web server.</p>

<p><a class="target" name="mock">
<h2>Using mock objects</h2>
</a></p>
<p>Let's move further into the future.</p>
<p>Assume that our logging class is tested and completed. Assume
also that we are testing another class that is required to write log
messages, say a <span class="new_code">SessionPool</span>. We want to
test a method that will probably end up looking like this...
<pre>
<strong>
class SessionPool {
    ...
    function logIn($username) {
        ...
        $this-&gt;_log-&gt;message("User $username logged in.");
        ...
    }
    ...
}
</strong>
</pre> In the spirit of reuse we are using our <span class="new_code">Log</span>
class. A conventional test case might look like this... <pre>
<strong>
&lt;?php
require_once('../classes/log.php');
require_once('../classes/session_pool.php');

class TestOfSessionLogging extends UnitTestCase {
    
    function setUp() {
        @unlink('/temp/test.log');
    }
    
    function tearDown() {
        @unlink('/temp/test.log');
    }
    
    function testLogInIsLogged() {
        $log = new Log('/temp/test.log');
        $session_pool = &amp;new SessionPool($log);
        $session_pool-&gt;logIn('fred');
        $messages = file('/temp/test.log');
        $this-&gt;assertEqual($messages[0], "User fred logged in.\n");
    }
}
?&gt;</strong>
</pre> This test case design is not all bad, but it could be improved. We are
spending time fiddling with log files which are not part of our test.
Worse, we have created close ties with the <span class="new_code">Log</span>
class and this test. What if we don't use files any more, but use ths <em>syslog</em>
library instead? Did you notice the extra carriage return in the
message? Was that added by the logger? What if it also added a time
stamp or other data?
</p>
<p>The only part that we really want to test is that a particular
message was sent to the logger. We reduce coupling if we can pass in a
fake logging class that simply records the message calls for testing,
but takes no action. It would have to look exactly like our original
though.</p>
<p>If the fake object doesn't write to a file then we save on
deleting the file before and after each test. We could save even more
test code if the fake object would kindly run the assertion for us.
<p></p>
Too good to be true? Luckily we can create such an object easily... <pre>
&lt;?php
require_once('../classes/log.php');
require_once('../classes/session_pool.php');<strong>
Mock::generate('Log');</strong>

class TestOfSessionLogging extends UnitTestCase {
    
    function testLogInIsLogged() {<strong>
        $log = &amp;new MockLog();
        $log-&gt;expectOnce('message', array('User fred logged in.'));</strong>
        $session_pool = &amp;new SessionPool($log);
        $session_pool-&gt;logIn('fred');
    }
}
?&gt;
</pre> The test will be triggered when the call to <span class="new_code">message()</span>
is invoked on the <span class="new_code">MockLog</span> object. The mock
call will trigger a parameter comparison and then send the resulting
pass or fail event to the test display. Wildcards can be included here
too so as to prevent tests becoming too specific.
</p>
<p>If the mock reaches the end of the test case without the method
being called, the <span class="new_code">expectOnce()</span> expectation
will trigger a test failure. In other words the mocks can detect the
absence of behaviour as well as the presence.</p>
<p>The mock objects in the SimpleTest suite can have arbitrary
return values set, sequences of returns, return values selected
according to the incoming arguments, sequences of parameter expectations
and limits on the number of times a method is to be invoked.</p>
<p>For this test to run the mock objects library must have been
included in the test suite, say in <em>all_tests.php</em>.</p>

<p><a class="target" name="web">
<h2>Web page testing</h2>
</a></p>
<p>One of the requirements of web sites is that they produce web
pages. If you are building a project top-down and you want to fully
integrate testing along the way then you will want a way of
automatically navigating a site and examining output for correctness.
This is the job of a web tester.</p>
<p>The web testing in SimpleTest is fairly primitive, there is no
JavaScript for example. To give an idea here is a trivial example where
a home page is fetched, from which we navigate to an "about" page and
then test some client determined content.
<pre>
&lt;?php<strong>
require_once('simpletest/web_tester.php');</strong>
require_once('simpletest/reporter.php');
<strong>
class TestOfAbout extends WebTestCase {
    
    function setUp() {
        $this-&gt;get('http://test-server/index.php');
        $this-&gt;click('About');
    }
    
    function testSearchEngineOptimisations() {
        $this-&gt;assertTitle('A long title about us for search engines');
        $this-&gt;assertPattern('/a popular keyphrase/i');
    }
}</strong>
$test = &amp;new TestOfAbout();
$test-&gt;run(new HtmlReporter());
?&gt;
</pre> With this code as an acceptance test you can ensure that the content
always meets the specifications of both the developers and the other
project stakeholders.
</p>
<p><a href="http://sourceforge.net/projects/simpletest/"><img
	src="http://sourceforge.net/sflogo.php?group_id=76550&amp;type=5"
	width="210" height="62" border="0" alt="SourceForge.net Logo"></a></p>

</div>
References and related information...
<ul>
	<li><a
		href="https://sourceforge.net/project/showfiles.php?group_id=76550&amp;release_id=153280">Download
	PHP Simple Test</a> from <a
		href="http://sourceforge.net/projects/simpletest/">SourceForge</a>.</li>
	<li>The <a href="http://simpletest.sourceforge.net/">developer's
	API for SimpleTest</a> gives full detail on the classes and assertions
	available.</li>
</ul>
<div class="menu_back">
<div class="menu"><span class="chosen">SimpleTest</span> | <a
	href="overview.html">Overview</a> | <a
	href="unit_test_documentation.html">Unit tester</a> | <a
	href="group_test_documentation.html">Group tests</a> | <a
	href="mock_objects_documentation.html">Mock objects</a> | <a
	href="partial_mocks_documentation.html">Partial mocks</a> | <a
	href="reporter_documentation.html">Reporting</a> | <a
	href="expectation_documentation.html">Expectations</a> | <a
	href="web_tester_documentation.html">Web tester</a> | <a
	href="form_testing_documentation.html">Testing forms</a> | <a
	href="authentication_documentation.html">Authentication</a> | <a
	href="browser_documentation.html">Scriptable browser</a></div>
</div>
<div class="copyright">Copyright<br>
Marcus Baker 2006</div>
</body>
</html>
